package com.feiwo.nonego.rpc.serialization.json;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.feiwo.nonego.rpc.serialization.api.Serialization;
import com.feiwo.nonego.rpc.serialization.api.exception.SerializerException;
import com.feiwo.nonego.rpc.spi.annotation.SPIClass;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Objects;

/**
 *
 *
 * @author feiwo 2025-08-13
 */
@SPIClass
public class JsonSerialization implements Serialization {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    static {
        var dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        OBJECT_MAPPER.setDateFormat(dateFormat);
        OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        OBJECT_MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
        OBJECT_MAPPER.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
        OBJECT_MAPPER.configure(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT, false);
        OBJECT_MAPPER.disable(SerializationFeature.FLUSH_AFTER_WRITE_VALUE);
        OBJECT_MAPPER.disable(SerializationFeature.CLOSE_CLOSEABLE);
        OBJECT_MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);
        OBJECT_MAPPER.configure(JsonParser.Feature.IGNORE_UNDEFINED, true);
    }

    @Override
    public <T> byte[] serialize(T obj) {
        if (Objects.isNull(obj)) {
            throw new SerializerException("serialization object is null");
        }
        var bytes = new byte[0];
        try {
            bytes = OBJECT_MAPPER.writeValueAsBytes(obj);
        } catch (JsonProcessingException e) {
            throw new SerializerException(e.getMessage(), e);
        }
        return bytes;
    }

    @Override
    public <T> T deserialize(byte[] data, Class<T> clazz) {
        if (Objects.isNull(data)) {
            throw new SerializerException("deserialization data is null");
        }
        T obj = null;
        try {
            obj = OBJECT_MAPPER.readValue(data, clazz);
        } catch (IOException e) {
            throw new SerializerException(e.getMessage(), e);
        }
        return obj;
    }
}
